﻿using Cms.Application.Admin.Presenters;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Cms.Domain;
using Cms.Application.Admin.Views;
using Moq;
using System.Collections.Generic;

namespace Cms.Tests.Unit.Application.Admin.Presenters
{
    [TestClass]
    public class EditPagePresenterTests : BasePresenterTests
    {
        private Site _site;
        private Locale _localeEn;
        private Locale _localeSe;
        private Administrator _admin;
        private Mock<IEditPageView> _viewMock;

        private void Prepare()
        {
            InitRepositoryFactoryMock();
            _admin = new Administrator();
            _site = new Site {Domain = "www.fredium.com"};
            _admin.CurrentSite = _site;
            MasterTemplate mt = new MasterTemplate {ID = 1};
            _site.MasterTemplates.Add(mt);
            _site.DefaultMasterTemplate = mt;
            DetailTemplate dt = new DetailTemplate {ID = 1};
            _site.DetailTemplates.Add(dt);
            _site.DefaultDetailTemplate = dt;
            _localeEn = new Locale { ID = 1, Site = _site };
            _localeSe = new Locale { ID = 2, Site = _site };
            _site.Locales.Add(_localeEn);
            _site.Locales.Add(_localeSe);
            _site.DefaultLocale = _localeEn;
            AdministratorRepositoryMock.Setup(a => a.GetAdministrator(1)).Returns(_admin);
            _viewMock = new Mock<IEditPageView>();
            _viewMock.SetupAllProperties();
            _viewMock.Setup(v => v.AdministratorID).Returns(1);
            _viewMock.Setup(v => v.Localization).Returns("en-US");
            _viewMock.Setup(v => v.ContextTranslationFile).Returns("Admin/Translations/EditPage.xml");
        }

        [TestMethod]
        public void Initialize_AdministratorsCurrentSelectedLocaleHasValue_SelectedLocaleIDIsSet()
        {
            Prepare();
            _admin.CurrentSiteLocale = _localeSe;
            _viewMock.Setup(v => v.PageID).Returns(-1);
            EditPagePresenter presenter = new EditPagePresenter(_viewMock.Object, FactoryMock.Object);
            presenter.Initialize();
            Assert.AreEqual(2, _viewMock.Object.SelectedLocaleID);
        }

        [TestMethod]
        public void Initialize_NewPage_AdministratorHasAlreadySelectedAFolder_SelectedFolderIDIsUpdated()
        {
            Prepare();
            _admin.SelectedFolderID = 3;
            _viewMock.Setup(v => v.PageID).Returns(-1);
            Folder folder3 = new Folder {ID = 3};
            FolderRepositoryMock.Setup(m => m.GetFolder(3)).Returns(folder3);
            EditPagePresenter presenter = new EditPagePresenter(_viewMock.Object, FactoryMock.Object);
            presenter.Initialize();
            Assert.AreEqual(3, _viewMock.Object.SelectedFolderID);
        }

        [TestMethod]
        public void Initialize_CheckIfSetVersionsIsCalled_MethodIsCalled()
        {
            Prepare();
            _viewMock.Setup(v => v.PageID).Returns(-1);
            EditPagePresenter presenter = new EditPagePresenter(_viewMock.Object, FactoryMock.Object);
            presenter.Initialize();
            _viewMock.Verify(m => m.SetVersions(It.IsAny<IList<ContentTranslationVersion>>(), It.IsAny<int>()), Times.Once());
        }
        
        [TestMethod]
        public void Initialize_NewPage_CheckThatTheRightMasterTemplateIsSelected_IdIsTwo()
        {
            Prepare();
            _viewMock.Setup(v => v.PageID).Returns(-1);
            MasterTemplate mt = new MasterTemplate { ID = 2 };
            _site.MasterTemplates.Add(mt);
            _site.DefaultMasterTemplate = mt;
            EditPagePresenter presenter = new EditPagePresenter(_viewMock.Object, FactoryMock.Object);
            presenter.Initialize();
            Assert.AreEqual(2, _viewMock.Object.SelectedMasterTemplateID);
        }

        [TestMethod]
        public void Initialize_NewPage_CheckThatTheRightDetailTemplateIsSelected_IdIsTwo()
        {
            Prepare();
            _viewMock.Setup(v => v.PageID).Returns(-1);
            DetailTemplate dt = new DetailTemplate { ID = 2 };
            _site.DetailTemplates.Add(dt);
            _site.DefaultDetailTemplate = dt;
            EditPagePresenter presenter = new EditPagePresenter(_viewMock.Object, FactoryMock.Object);
            presenter.Initialize();
            Assert.AreEqual(2, _viewMock.Object.SelectedDetailTemplateID);
        }
        
        [TestMethod]
        public void Initialize_EditPage_CheckThatRefreshPropertiesIsCalled_IsCalled()
        {
            Prepare();
            Page page = new Page() {ID = 1, Name = "Start page", Filename = "default.aspx"};
            PageRepositoryMock.Setup(m => m.GetPage(1)).Returns(page);
            page.MasterTemplate = _site.DefaultMasterTemplate;
            page.DetailTemplate = _site.DefaultDetailTemplate;
            _viewMock.Setup(v => v.PageID).Returns(1);
            EditPagePresenter presenter = new EditPagePresenter(_viewMock.Object, FactoryMock.Object);
            presenter.Initialize();
            Assert.AreEqual("Start page", _viewMock.Object.Name); // If name is set, then RefreshProperties was called
        }
        
        [TestMethod]
        public void RefreshProperties_SetBasicProperties_AllSet()
        {
            Prepare();
            Page page = new Page()
                            {
                                ID = 1, 
                                Name = "Start page", 
                                Filename = "default.aspx",
                                SortKey = "a",
                                HeadHtml = "head",
                                BodyTopHtml = "top",
                                BodyBottomHtml = "bottom"
                            };
            PageRepositoryMock.Setup(m => m.GetPage(1)).Returns(page);
            page.MasterTemplate = _site.DefaultMasterTemplate;
            page.DetailTemplate = _site.DefaultDetailTemplate;
            _viewMock.Setup(v => v.PageID).Returns(1);
            EditPagePresenter presenter = new EditPagePresenter(_viewMock.Object, FactoryMock.Object);
            presenter.Initialize();
            Assert.AreEqual("Start page", _viewMock.Object.Name);
            Assert.AreEqual("default", _viewMock.Object.Filename); // Strip .aspx extension
            Assert.AreEqual("a", _viewMock.Object.SortKey);
            Assert.AreEqual(-1, _viewMock.Object.SelectedFolderID); // No folder set
            Assert.AreEqual("head", _viewMock.Object.HeadHtml);
            Assert.AreEqual("top", _viewMock.Object.BodyTopHtml);
            Assert.AreEqual("bottom", _viewMock.Object.BodyBottomHtml);
        }
        
        [TestMethod]
        public void RefreshProperties_SetLocalizedProperties_AllSet()
        {
            Prepare();
            Page page = new Page()
            {
                ID = 1,
                Name = "Start page",
                Filename = "default.aspx",
            };
            PageRepositoryMock.Setup(m => m.GetPage(1)).Returns(page);
            page.MasterTemplate = _site.DefaultMasterTemplate;
            page.DetailTemplate = _site.DefaultDetailTemplate;
            page.LocalizedProperties.Add(_localeEn.ID, 
                new PageLocalizedProperties()
                     {
                         Title = "title",
                         Description = "desc",
                         Keywords = "keywords"
                     });
            _admin.CurrentSiteLocale = _localeEn;
            _viewMock.Setup(v => v.PageID).Returns(1);
            EditPagePresenter presenter = new EditPagePresenter(_viewMock.Object, FactoryMock.Object);
            presenter.Initialize();
            Assert.AreEqual("title", _viewMock.Object.PageTitle);
            Assert.AreEqual("desc", _viewMock.Object.PageDescription);
            Assert.AreEqual("keywords", _viewMock.Object.PageKeywords);
        }

        [TestMethod]
        public void RefreshProperties_PageHasFolder_FolderIsSet()
        {
            Prepare();
            Folder folder = new Folder() { ID = 66 };
            Page page = new Page()
            {
                ID = 1,
                Filename = "default.aspx",
                Folder = folder
            };
            PageRepositoryMock.Setup(m => m.GetPage(1)).Returns(page);
            page.MasterTemplate = _site.DefaultMasterTemplate;
            page.DetailTemplate = _site.DefaultDetailTemplate;
            _viewMock.Setup(v => v.PageID).Returns(1);
            EditPagePresenter presenter = new EditPagePresenter(_viewMock.Object, FactoryMock.Object);
            presenter.RefreshProperties();
            Assert.AreEqual(66, _viewMock.Object.SelectedFolderID);
        }
        
        [TestMethod]
        public void SaveSelectedLocale_TestThatAdminIsSaved_Success()
        {
            Prepare();
            _admin.CurrentSiteLocale = _localeSe;
            _viewMock.Setup(v => v.SelectedLocaleID).Returns(1); // _localeEn
            LocaleRepositoryMock.Setup(m => m.GetLocale(1)).Returns(_localeEn);
            EditPagePresenter presenter = new EditPagePresenter(_viewMock.Object, FactoryMock.Object);
            presenter.SaveSelectedLocale();
            Assert.AreSame(_localeEn, _admin.CurrentSiteLocale);
        }

        [TestMethod]
        public void SetVersions_NewPage_EmptyList()
        {
            Prepare();
            _viewMock.Setup(v => v.PageID).Returns(-1); // new page
            EditPagePresenter presenter = new EditPagePresenter(_viewMock.Object, FactoryMock.Object);
            presenter.SetVersions();
            _viewMock.Verify(m => m.SetVersions(It.Is<IList<ContentTranslationVersion>>(i => i.Count == 0), It.Is<int>(i => i.Equals(-1))));
        }
        
        [TestMethod]
        public void SetVersions_EditPageWithThreeVersions_ViewHasThreeVersions()
        {
            Prepare();
            Page page = new Page()
            {
                ID = 1,
                Filename = "default.aspx"
            };
            Content content = new Content
                                  {
                                      ID = 1,
                                      Name = "pcMain Content"
                                  };
            page.AddContentLink("pcMain", content);
            ContentTranslationVersion ctv;
            ctv = content.AddVersion(_localeEn, 1, "some text version 1", "", _admin);
            page.GetContentSet(_localeEn).TranslationVersions.Add(ctv);
            ctv = content.AddVersion(_localeEn, 2, "some text version 2", "", _admin);
            page.GetContentSet(_localeEn).TranslationVersions.Add(ctv);
            ctv = content.AddVersion(_localeEn, 3, "some text version 3", "", _admin);
            page.GetContentSet(_localeEn).TranslationVersions.Add(ctv);
            _viewMock.Setup(v => v.PageID).Returns(1); // edit page
            _viewMock.Setup(v => v.SelectedLocaleID).Returns(1); // _localeEn
            PageRepositoryMock.Setup(m => m.GetPage(1)).Returns(page);
            EditPagePresenter presenter = new EditPagePresenter(_viewMock.Object, FactoryMock.Object);
            presenter.SetVersions();
            _viewMock.Verify(m => m.SetVersions(It.Is<IList<ContentTranslationVersion>>(i => i.Count == 3), It.Is<int>(i => i.Equals(-1))));
            _viewMock.Verify(m => m.SetVersions(It.Is<IList<ContentTranslationVersion>>(i => i[0].Html == "some text version 3"), It.Is<int>(i => i.Equals(-1))));
        }
        
        [TestMethod]
        public void Validate_NoName_Error1()
        {
            Prepare();
            _viewMock.Setup(v => v.PageID).Returns(-1); // new page
            _viewMock.Setup(v => v.CurrentTab).Returns("basicproperties");
            _viewMock.Setup(v => v.Name).Returns("");
            _viewMock.Setup(v => v.Filename).Returns("");
            EditPagePresenter presenter = new EditPagePresenter(_viewMock.Object, FactoryMock.Object);
            presenter.Validate();
            Assert.IsTrue(presenter.ValidationErrorCodes.Contains(1));
        }
        
        [TestMethod]
        public void Validate_NoFilename_Error2()
        {
            Prepare();
            _viewMock.Setup(v => v.PageID).Returns(-1); // new page
            _viewMock.Setup(v => v.CurrentTab).Returns("basicproperties");
            _viewMock.Setup(v => v.Name).Returns("");
            _viewMock.Setup(v => v.Filename).Returns("");
            EditPagePresenter presenter = new EditPagePresenter(_viewMock.Object, FactoryMock.Object);
            presenter.Validate();
            Assert.IsTrue(presenter.ValidationErrorCodes.Contains(2));
        }
        
        [TestMethod]
        public void Validate_FilenameNotAllowed_Error3()
        {
            Prepare();
            Page page = new Page()
            {
                ID = 2,
                Filename = "default.aspx",
                Site = _site
            };
            _site.Pages.Add(page);
            _viewMock.Setup(v => v.PageID).Returns(-1); // new page
            _viewMock.Setup(v => v.CurrentTab).Returns("basicproperties");
            _viewMock.Setup(v => v.Name).Returns("Start");
            _viewMock.Setup(v => v.Filename).Returns("default");
            EditPagePresenter presenter = new EditPagePresenter(_viewMock.Object, FactoryMock.Object);
            presenter.Validate();
            Assert.IsTrue(presenter.ValidationErrorCodes.Contains(3));
        }
        
        [TestMethod]
        public void Validate_FilenameIsNotSystemCompliant_Error4()
        {
            Prepare();
            _viewMock.Setup(v => v.PageID).Returns(1);
            _viewMock.Setup(v => v.CurrentTab).Returns("basicproperties");
            _viewMock.Setup(v => v.Name).Returns("Start");
            EditPagePresenter presenter = new EditPagePresenter(_viewMock.Object, FactoryMock.Object);
            _viewMock.Setup(v => v.Filename).Returns("åäö");
            presenter.Validate();
            Assert.IsTrue(presenter.ValidationErrorCodes.Contains(4));
            _viewMock.Setup(v => v.Filename).Returns("a b");
            presenter.Validate();
            Assert.IsTrue(presenter.ValidationErrorCodes.Contains(4));
        }
        
        [TestMethod]
        public void GetBasicPropertiesViewData_ViewHasCorrectValues_PageIsUpdatedAccordingToView()
        {
            Prepare();
            Page page = new Page()
            {
                ID = 1,
            };
            Folder folder = new Folder() { ID = 2 };
            _site.Pages.Add(page);
            FolderRepositoryMock.Setup(m => m.GetFolder(2)).Returns(folder);
            SiteRepositoryMock.Setup(m => m.GetMasterTemplate(1)).Returns(_site.DefaultMasterTemplate);
            SiteRepositoryMock.Setup(m => m.GetDetailTemplate(1)).Returns(_site.DefaultDetailTemplate);
            _viewMock.Setup(v => v.PageID).Returns(1); // new page
            _viewMock.Setup(v => v.Name).Returns("Start");
            _viewMock.Setup(v => v.Filename).Returns("default");
            _viewMock.Setup(v => v.SelectedFolderID).Returns(2);
            _viewMock.Setup(v => v.SelectedMasterTemplateID).Returns(1);
            _viewMock.Setup(v => v.SelectedDetailTemplateID).Returns(1);
            _viewMock.Setup(v => v.SortKey).Returns("2010-01-01");
            _viewMock.Setup(v => v.HeadHtml).Returns("<meta />");
            _viewMock.Setup(v => v.BodyTopHtml).Returns("<script top />");
            _viewMock.Setup(v => v.BodyBottomHtml).Returns("<script bottom />");
            EditPagePresenter presenter = new EditPagePresenter(_viewMock.Object, FactoryMock.Object);
            presenter.GetBasicPropertiesViewData(page);
            Assert.AreEqual("Start", page.Name);
            Assert.AreEqual("default.aspx", page.Filename);
            Assert.AreSame(folder, page.Folder);
            Assert.AreSame(_site.DefaultMasterTemplate, page.MasterTemplate);
            Assert.AreSame(_site.DefaultDetailTemplate, page.DetailTemplate);
            Assert.AreEqual("2010-01-01", page.SortKey);
            Assert.AreEqual("<meta />", page.HeadHtml);
            Assert.AreEqual("<script top />", page.BodyTopHtml);
            Assert.AreEqual("<script bottom />", page.BodyBottomHtml);
        }
        
        [TestMethod]
        public void GetLocalizedPropertiesViewData_ViewHasCorrectValues_PageIsUpdatedAccordingToView()
        {
            Prepare();
            Page page = new Page()
            {
                ID = 1,
            };
            _viewMock.Setup(v => v.PageTitle).Returns("Fredium CMS");
            _viewMock.Setup(v => v.PageDescription).Returns("Fredium is the shit. Yeah.");
            _viewMock.Setup(v => v.PageKeywords).Returns("CMS");
            _viewMock.Setup(v => v.SelectedLocaleID).Returns(1);
            EditPagePresenter presenter = new EditPagePresenter(_viewMock.Object, FactoryMock.Object);
            presenter.GetLocalizedPropertiesViewData(page);
            Assert.AreEqual(1, page.LocalizedProperties.Count);
            Assert.AreEqual("Fredium CMS", page.LocalizedProperties[1].Title);
            Assert.AreEqual("Fredium is the shit. Yeah.", page.LocalizedProperties[1].Description);
            Assert.AreEqual("CMS", page.LocalizedProperties[1].Keywords);
        }

        [TestMethod]
        public void GetPagePreviewUrl_ExistingPage_OK()
        {
            Prepare();
            Folder folder = new Folder()
                                {
                                    ID = 1, 
                                    Site = _site,
                                    Name = "test"
                                };

            Page page = new Page()
                            {
                                ID = 1,
                                Site = _site,
                                Folder = folder,
                                Filename = "testpage.aspx"
                            };
            PageRepositoryMock.Setup(m => m.GetPage(1)).Returns(page);
            _viewMock.Setup(v => v.PageID).Returns(1);
            _viewMock.Setup(v => v.SelectedLocaleID).Returns(1); // _localeEn
            _viewMock.Setup(v => v.SelectedVersionID).Returns(1);
            EditPagePresenter presenter = new EditPagePresenter(_viewMock.Object, FactoryMock.Object);
            const string expectedUrl = "http://www.fredium.com/test/testpage.aspx?PreviewMode=Page&VersionID=1";
            Assert.AreEqual(expectedUrl, presenter.GetPagePreviewUrl());
        }
    }
}
